function CreateHandlerTimerWithDtor(obj, cb, dtor, interval, repeats, firstime)
	local handler = obj:castToWheelRoutineType():NewUniqueRoutineType()
	obj:castToWheelTimerOwner():CreateTimer(
		CastCallableWithDtor(cb, dtor), handler, interval, repeats, firstime)
	return handler
end

function CreateHandlerTimer(obj, cb, interval, repeats, firstime)
	local handler = obj:castToWheelRoutineType():NewUniqueRoutineType()
	obj:castToWheelTimerOwner():CreateTimer(
		CastCallable(cb), handler, interval, repeats, firstime)
	return handler
end

function CreateTimer(obj, cb, handler, interval, repeats, firstime)
	obj:castToWheelTimerOwner():CreateTimer(
		CastCallable(cb), handler, interval, repeats, firstime)
end

function CreateTimerX(obj, cb, interval, repeats, firstime)
	obj:castToWheelTimerOwner():CreateTimerX(
		CastCallable(cb), interval, repeats, firstime)
end

function CreateOrRepushTimer(obj, cb, handler, interval, repeats, firstime)
	local pWheelTimerOwner = obj:castToWheelTimerOwner()
	if handler then
		local pTimer = pWheelTimerOwner:FindTimer(handler)
		if pTimer then
			pTimer:RePush(firstime)
			return
		end
	end
	if not handler then
		handler = obj:castToWheelRoutineType():NewUniqueRoutineType()
	end
	pWheelTimerOwner:CreateTimer(
		CastCallable(cb), handler, interval, repeats, firstime)
	return handler
end

function RemoveTimer(obj, handler)
	obj:castToWheelTimerOwner():RemoveTimers(handler)
end

function AddEvent4Object(obj, cb)
	obj:GetMapInstance():AddEvent(cb)
end

function DoItOrDelay(obj, cb, delay, type)
	if delay and delay > 0 then
		if type then
			obj:castToWheelTimerOwner():CreateTimer(
				CastCallable(cb), type, delay, 1)
		else
			obj:castToWheelTimerOwner():CreateTimerX(
				CastCallable(cb), delay, 1)
		end
	else
		cb()
	end
end

function FastRandomByWeightValue(weights)
	local sum = 0
	for i, weight in ipairs(weights) do
		sum = sum + weight
	end
	if sum ~= 0 then
		local odds = math.random(sum)
		for i, weight in ipairs(weights) do
			if odds > weight then
				odds = odds - weight
			else
				return i
			end
		end
	end
end

function CanCastWithoutLearnSpell2Target(
	obj, pTarget, spellID, spellLevel, spellCastFlags, tgtEffPos, args)
	return obj:CanCastWithoutLearnSpell2Target(pTarget,
		spellID, spellLevel or 1, spellCastFlags or 0,
		tgtEffPos or vector3f_INVALID, args or emptyStringView)
end

function CanCastWithoutLearnSpell(
	obj, spellID, spellLevel, spellCastFlags, tgtEffPos, args)
	return obj:CanCastWithoutLearnSpell(
		spellID, spellLevel or 1, spellCastFlags or 0,
		tgtEffPos or vector3f_INVALID, args or emptyStringView)
end

function CastWithoutLearnSpell2Target(
	obj, pTarget, spellID, spellLevel, spellInstGuid, tgtEffPos, args)
	return obj:CastWithoutLearnSpell2Target(pTarget,
		spellID, spellLevel or 1, spellInstGuid or 0,
		tgtEffPos or vector3f_INVALID, args or emptyStringView)
end

function CastWithoutLearnSpell(
	obj, spellID, spellLevel, spellInstGuid, tgtEffPos, args)
	return obj:CastWithoutLearnSpell(
		spellID, spellLevel or 1, spellInstGuid or 0,
		tgtEffPos or vector3f_INVALID, args or emptyStringView)
end

function CanCastSpell2Target(
	obj, pTarget, spellID, spellCastFlags, tgtEffPos, args)
	return obj:CanCastSpell2Target(pTarget, spellID, spellCastFlags or 0,
		tgtEffPos or vector3f_INVALID, args or emptyStringView)
end

function CanCastSpell(obj, spellID, spellCastFlags, tgtEffPos, args)
	return obj:CanCastSpell(spellID, spellCastFlags or 0,
		tgtEffPos or vector3f_INVALID, args or emptyStringView)
end

function CastSpell2Target(
	obj, pTarget, spellID, spellInstGuid, tgtEffPos, args)
	return obj:CastSpell2Target(pTarget, spellID, spellInstGuid or 0,
		tgtEffPos or vector3f_INVALID, args or emptyStringView)
end

function CastSpell(obj, spellID, spellInstGuid, tgtEffPos, args)
	return obj:CastSpell(spellID, spellInstGuid or 0,
		tgtEffPos or vector3f_INVALID, args or emptyStringView)
end

function MoveToTarget(obj, pTarget, dozeDist, dullDist, keepDist, facePos)
	obj:MoveToTarget(pTarget, dozeDist or 0, dullDist or 0, keepDist or 0,
		facePos or vector3f_INVALID)
end

function MoveToPosition(obj, pTarget, dozeDist, dullDist, keepDist, facePos)
	obj:MoveToPosition(pTarget, dozeDist or 0, dullDist or 0, keepDist or 0,
		facePos or vector3f_INVALID)
end

function CheckObjectAlive(obj)
	return obj:is_object_alive() and obj:IsInWorld() and not obj:IsDead()
end

function RunScriptFile(scriptFile, ...)
	if scriptFile and DoScriptFile(scriptFile) then
		return main(...)
	end
end

function LoadConfigFile(configFile)
	if configFile and DoScriptFile(configFile) then
		return cfg
	end
end

function CallMethod(t, methodName, ...)
	local method = t and t[methodName]
	if method then
		return method(t, ...)
	end
end

function CallStaticMethod(t, methodName, ...)
	local method = t and t[methodName]
	if method then
		return method(...)
	end
end

function AddMethod_OnSendMessage(t)
	t.OnSendMessage = function(t, funcName, args)
		local f = t[funcName]
		if type(f) == 'function' then
			if type(args) == 'table' then
				f(t, args, table.unpack(args))
			else
				f(t, args)
			end
		end
	end
end

function AddMethod_OnSendStaticMessage(t)
	t.OnSendMessage = function(funcName, args)
		local f = t[funcName]
		if type(f) == 'function' then
			if type(args) == 'table' then
				f(args, table.unpack(args))
			else
				f(args)
			end
		end
	end
end